from itertools import izip
from math import sqrt


def squared_distance(a, b):
    if type(a) is Vector and type(b) is Vector:
        return squared_distance_pp(a, b)
    elif type(a) is Box and type(b) is Box:
        return squared_distance_bb(a, b)
    else:
        raise TypeError()


def squared_distance_pp(point_a, point_b):
    return sum((a - b) ** 2 for a, b in izip(point_a, point_b))


def squared_distance_bb(box_a, box_b):
    return sum(max(a_min - b_max, b_min - a_max, 0) ** 2
               for a_min, a_max, b_min, b_max
               in izip(box_a.min, box_a.max, box_b.min, box_b.max))


def distance(a, b):
    return sqrt(squared_distance(a, b))


def manhattan_distance(point_a, point_b):
    return sum(abs(a - b) for a, b in izip(point_a, point_b))


def chebyshev_distance(point_a, point_b):
    return max(abs(a - b) for a, b in izip(point_a, point_b))


def dot_product(vector_a, vector_b):
    return sum(a * b for a, b in izip(vector_a, vector_b))


def contains(box, point):
    return all(min_x <= x < max_x
               for min_x, x, max_x in izip(box.min, point, box.max))


class Vector(object):

    def __init__(self, *args):
        self.__comps = tuple(args[0] if len(args) == 1 else args)

    @property
    def x(self):
        return self.__comps[0]

    @property
    def y(self):
        return self.__comps[1]

    @property
    def z(self):
        return self.__comps[2]

    @property
    def squared_magnitude(self):
        return sum(a ** 2 for a in self)

    @property
    def magnitude(self):
        return sqrt(self.squared_magnitude)

    def __add__(self, other):
        return Vector(a + b for a, b in izip(self, other))

    def __sub__(self, other):
        return Vector(a - b for a, b in izip(self, other))

    def __mul__(self, other):
        return Vector(a * other for a in self)

    def __rmul__(self, other):
        return Vector(a * other for a in self)

    def __div__(self, other):
        return Vector(a / other for a in self)

    def __neg__(self):
        return Vector(-a for a in self)

    def __abs__(self):
        return self.magnitude

    def __str__(self):
        return '[' + ', '.join(str(a) for a in self) + ']'

    def __repr__(self):
        return '%s(%s)' % (type(self).__name__,
                           ', '.join(repr(a) for a in self))

    def __cmp__(self, other):
        return cmp(self.__comps, other.__comps)

    def __hash__(self):
        return hash(self.__comps)

    def __iter__(self):
        return iter(self.__comps)

    def __nonzero__(self):
        return any(self)

    def __getitem__(self, axis):
        return self.__comps[axis]

    def __len__(self):
        return len(self.__comps)


class Box(object):
    def __init__(self, min, max):
        self.__min = Vector(min)
        self.__max = Vector(max)

    @property
    def min(self):
        return self.__min

    @property
    def max(self):
        return self.__max

    @property
    def center(self):
        return (self.min + self.max) / 2

    @property
    def size(self):
        return self.max - self.min

    @property
    def bounds(self):
        return self

    def __contains__(self, other):
        return contains(self, other)

    """
    def contains(self, other):
        return self.contains_point(other)

    def contains_point(self, point):
        return all(a_min <= a < a_max
                   for a_min, a, a_max in zip(self.min, point, self.max))

    def intersects(self, other):
        return self.intersects_box(other)

    def intersects_box(self, other):
        return (self.min.x < other.max.x and other.min.x < self.max.x
                and self.min.y < other.max.y and other.min.y < self.max.y)
        """

    def __eq__(self, other):
        return self.min == other.min and self.max == other.max

    def __str__(self):
        return repr(self)

    def __repr__(self):
        return 'Box(%s, %s)' % (tuple(self.min), tuple(self.max))
